#!/bin/bash
# Build script for mecloud, version 0.5
# 
# Wenbo Wang (1ball.w@gmail.com)
# 2012.03.28

set -e

unpack()
{
	case $2 in
		tar.gz | tar.bz2 | tar.xz)
			tar -xvf "$1" -C "$3"
			;;
		zip)
			unzip "$1" -d "$3"
			;;
		*)
			echo "Unkown package format for \"$1\""
			return 1
			;;
	esac
	return 0
}

recurs_build_dir()
{
	local LOOP_ACTION='return'
	OPTIND=1
	while getopts "c" FLAG
	do
		case "$FLAG" in
			c)
				LOOP_ACTION='continue'
				;;
		esac
	done
	shift $((OPTIND - 1))
	for PKG in ${BUILD_LIST[@]}; do
		(
		source ${SPECS}/${PKG}/spec
		if [ -z "$PKG_DIR" ]; then
			PKG_DIR="${BUILD_DIR}/${PKG}-${VERSION}"
		else
			PKG_DIR="${BUILD_DIR}/${PKG_DIR}"
		fi
		if [ -d $PKG_DIR/.build ]; then
			cd $PKG_DIR/.build
		elif [ -d $PKG_DIR ]; then
			cd $PKG_DIR
		else
			echo "Directory \"$PKG_DIR\" not found."
			exit 1
		fi
		$@ || $LOOPACTION
		)
	done
}

build_apps()
{
	for PKG in ${BUILD_LIST[@]}; do
		(
		source ${SPECS}/${PKG}/spec
		if [ -z "$PKG_DIR" ]; then
			PKG_DIR="${BUILD_DIR}/${PKG}-${VERSION}"
		else
			PKG_DIR="${BUILD_DIR}/${PKG_DIR}"
		fi
		if [ -z "$PKG_FILE_NAME" ]; then
			if [ -n "$PKG_URL" ]; then
				PKG_FILE_NAME=${PKG_URL##*/}
			else
				echo "Package $PKG undefined. Exiting..."
				exit 1
			fi
		fi
		if [ -z "$SUFFIX" ]; then
			SUFFIX=${PKG_FILE_NAME##*.}
			case $SUFFIX in
				gz | bz2 | xz)
					SUFFIX=tar.$SUFFIX
					;;
			esac
		fi
		if [ ! -d "${PKG_DIR}" ]; then
			if [ ! -r "${SRC_DIR}/${PKG_FILE_NAME}" ] ; then
				if [ -n "$PKG_URL" ]; then
					wget -P $SRC_DIR $PKG_URL
				else
					echo "Package ${PKG}-${VERSION} not found. Build failed."
					exit 1
				fi
			fi
			unpack "${SRC_DIR}/${PKG_FILE_NAME}" $SUFFIX ${BUILD_DIR}
		fi
		export PKG PKG_DIR PATCHES VERSION
		cd ${PKG_DIR}
		# Execute any script or binary: shell, perl, python, java, etc... with env variables exported to it
		# pre-build can be used to do patching job
		if [ ! -f .patched ]; then
			for PATCH_URL in ${PATCHES[@]}; do
				PATCH_FILE=${PATCH_URL##*/}
				if [ ! -r $SPECS/$PKG/$PATCH_FILE ]; then
					wget -P $SPECS/$PKG/ $PATCH_URL
				fi
			done
			if ls $SPECS/$PKG/*.patch &> /dev/null; then
				for PATCH_FILE in $SPECS/$PKG/*.patch; do
					patch -Np1 < $PATCH_FILE
				done
			fi
			[ -x ${SPECS}/${PKG}/pre-build ] && ${SPECS}/${PKG}/pre-build
			touch .patched
		fi
		if [ ! -f .built ]; then
			if [ -x ${SPECS}/${PKG}/build ]; then
				${SPECS}/${PKG}/build
			else
				if [ -r Makefile ] && [ ! -x configure ]; then
					make
					make install
				elif [ -x configure ]; then
					if [ ! -f .configured ]; then
						mkdir -p ${PKG_DIR}/.build
						cd ${PKG_DIR}/.build
						../configure ${CONFIGFLAGS}
						touch ${PKG_DIR}/.configured
					fi
					cd ${PKG_DIR}/.build
					make 
					make install
				elif [ -r ${PKG}.pro ]; then
					qmake
					make
				else
					echo "Don't know how to build package $PKG."
					exit 1
				fi
			fi
			touch "${PKG_DIR}/.built"
		fi
		if [ ! -f $PKG_DIR/.done ]; then
			# post-build can be used to fix installation problems
			[ -x ${SPECS}/${PKG}/post-build ] && ${SPECS}/${PKG}/post-build
			touch $PKG_DIR/.done
		else
			echo "${PKG} has already been built. Skip."
			exit
		fi
		)
	done
	echo -e "\nBuild complete."
}

make_clean_app()
{
	make clean
	cd $PKG_DIR
	rm -f .done .built
}

make_distclean_app()
{
	make DESTDIR=$FS_ROOT uninstall
	make distclean || make clean
	cd $PKG_DIR
	rm -f .tgt_installed .done .built .configured
}

make_uninstall_app()
{
	make uninstall
	cd $PKG_DIR
	rm -f .done
}

make_tgt_app()
{
	if [ "$TARGET_INSTALL" = n ]; then
		echo "Package $PKG does not required to be installed on target."
		return
	fi
	if [ $(dirname ${PWD}) = '.build' ]; then
		make DESTDIR=$FS_ROOT install
	else
		make PREFIX=${FS_ROOT}${PREFIX} prefix=${FS_ROOT}${PREFIX} install
	fi
}

tgt_app_post_install()
{
	# post-install can be used to fix target installation problems
	[ -x ${SPECS}/${PKG}/post-install ] && ${SPECS}/${PKG}/post-install
	touch .tgt_installed
}

clean_apps()
{
	recurs_build_dir make_clean_app
	echo -e "\nPackage ${BUILD_LIST[@]} clean complete."
}

distclean_apps()
{
	recurs_build_dir -c make_distclean_app
	echo -e "\nPackage ${BUILD_LIST[@]} dist clean complete."
}

uninstall_apps()
{
	echo "${BUILD_LIST[@]} are going to be uninstalled."
	while true; do
		echo -n "Proceed uninstall? (y/n) "
		read ANSWER
		case "$ANSWER" in
			n | N | no | NO)
				echo "Uninstall canceled."
				return
				;;
			y | Y | yes | YES)
				break
				;;
			*)
				;;
		esac
	done
	recurs_build_dir make_uninstall_app
	echo -e "\nPackage ${BUILD_LIST[@]} uninstall complete."
}

make_tgt_apps()
{
	build_apps ${BUILD_LIST[@]}
	rm -rf $FS_ROOT/* $FS_ROOT/.[!.]*
	recurs_build_dir make_tgt_app
	recurs_build_dir tgt_app_post_install
#	cd ${FS_ROOT}${BUILD_DEST}
#	sudo rm -rf include doc examples demos lib/dbus-1.0/include lib/glib-2.0/include share/doc share/gtk-doc
#	cd $FS_ROOT
#	find . -name "*.a" | xargs sudo rm -rf
#	find . -name "*.la" | xargs sudo rm -rf
#	find {,usr/}{,s}bin -type f | xargs sudo strip --strip-all
#	find {,usr/}lib -type f | xargs sudo strip --strip-debug
#	sudo tar -pczvf $MECLOUD_BIN --numeric-owner --owner=root --group=root .
#	sudo chown $(id -ru):$(id -rg) $MECLOUD_BIN
	echo -e "RootFS generation complete."
}

init_env()
{
	source build.conf
	cd $DEV_ROOT
	if [ ! -d SPEC ]; then
		echo "No SPEC directory found"
		exit 1
	fi
	mkdir -p "$SRC_DIR" "$BUILD_DIR" "$FS_ROOT"
}

print_help_and_exit()
{
	echo "Usage: $(basename $0) [Options] [Package Name]"
	echo "Options can be:"
	echo "	-b				Build only, don't make rootfs"
	echo "	-c				Clean packages"
	echo "	-d				Dist clean package build directories and rootfs"
	echo "	-i <directory>	Install package to <directory>"
	echo "	-u				Uninstall package from build system (Caution: this may break build system)"
	echo "	-h				Print this help"
	echo "Target can be:"
	echo "	\"all\" - Build all packages specified in SPECS/build_config"
	echo "	\"package name\" - Single or multiple package names overriding build_config"
	exit
}

init_env
# Default action
ACTION=make_tgt_apps

while getopts "bcdhi:u" OPT
do
	case "$OPT" in
		b)
			ACTION=build_apps
			;;
		c)
			ACTION=clean_apps
			;;
		d)
			ACTION=distclean_apps
			;;
		i)
			ACTION=make_tgt_apps
			export FS_ROOT="$OPTARG"
			;;
		u)
			ACTION=uninstall_apps
			;;
		h | *)
			print_help_and_exit
			;;
	esac
done
shift $((OPTIND - 1))

case "$1" in
	help | '')
		print_help_and_exit
		;;
	all)
		if [ "${#BUILD_LIST[@]}" = 0 ]; then
			echo "No package to build. Please define BUILD_LIST in build.conf"
			exit 1
		fi
		;;
	*)
		BUILD_LIST=($@)
		;;
esac

$ACTION
